package cn.kwq.project_manger.service.impl;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.kwq.project_manger.dtoUtils.ResProJDtoUtils;
import cn.kwq.project_manger.exception.SaveException;
import cn.kwq.project_manger.pojo.*;
import cn.kwq.project_manger.pojo.dto.*;
import cn.kwq.project_manger.repostitory.LikesRepository;
import cn.kwq.project_manger.repostitory.ProjectRepository;
import cn.kwq.project_manger.repostitory.ProjectTagRepository;
import cn.kwq.project_manger.repostitory.TagRepository;
import cn.kwq.project_manger.service.FilesService;
import cn.kwq.project_manger.service.ProjectService;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProjectServiceImpl implements ProjectService {

    @Autowired
    ProjectRepository projectRepository;

    @Autowired
    JPAQueryFactory jpaQueryFactory;

    @Autowired
    LikesRepository likesRepository;

    @Autowired
    ProjectTagRepository projectTagRepository;

    @Autowired
    TagRepository tagRepository;

    @Autowired
    FilesService filesService;

    @Autowired
    ResProJDtoUtils resDtoUtils;


    @Override
    @Transactional
    public PageDto findGame(FindGameDto findGameDto) {
        //当为空时候自动设为2，避免前端错误
        Integer instituteType = findGameDto.getInstituteType();
        if (instituteType == null) {
            findGameDto.setInstituteType(2);
        }
        Date now = DateUtil.parse(DateUtil.now(), "yyyy-MM-dd");

        QProject proj = QProject.project;
        //编辑距离结束时间
        Integer endDays = findGameDto.getEndDate();

        Date newEndDate=null;
        if (endDays != null ) {
            newEndDate = DateUtil.offset(now, DateField.DAY_OF_MONTH, endDays);
        }


        //DONE:  2022/11/16 16:51  分页后数据
        List<Project> fetch = jpaQueryFactory.select(proj)
                .from(proj)
                //文学院还是理学院
                .where(findGameDto.getInstituteType() == 2 ? proj.isNotNull().or(proj.isNull()) : proj.instituteType.eq(findGameDto.getInstituteType()))
                //比赛名字
                .where(findGameDto.getGameName()==null ? proj.isNotNull().or(proj.isNull()) : proj.projectName.like("%"+findGameDto.getGameName()+"%"))
                //学院限制
                .where(findGameDto.getCreateDepartment() == null ? proj.isNotNull().or(proj.isNull()) : proj.createDepartment.eq(findGameDto.getCreateDepartment()))
                //报名结束时间在用户选择的时间之前（结束=<用户选择的时间+现在）gt> lt<
                .where(findGameDto.getEndDate() == null ? proj.isNotNull().or(proj.isNull()) : proj.endTime.lt(newEndDate).or(proj.endTime.eq(newEndDate)))
                //报名现在还没结束
                .where(proj.endTime.after(now))
                //比赛类型
                .where(proj.type.eq(1))
                //审核已通过的
                .where(proj.status.eq(1))
                .orderBy(proj._super.updateDate.desc(),proj._super.createdDate.desc())
                .offset((long) (findGameDto.getPageNum() - 1) * findGameDto.getPageSize())
                .limit(findGameDto.getPageSize())
                .fetch();

        //DONE:  2022/11/16 16:51  总计
        Long total = jpaQueryFactory.select(proj.projectId.count())
                .from(proj)
                //文学院还是理学院
                .where(findGameDto.getInstituteType() == 2 ? proj.isNotNull().or(proj.isNull()) : proj.instituteType.eq(findGameDto.getInstituteType()))
                //比赛名字
                .where(findGameDto.getGameName()==null ? proj.isNotNull().or(proj.isNull()) : proj.projectName.like("%"+findGameDto.getGameName()+"%"))
                //学院限制
                .where(findGameDto.getCreateDepartment() == null ? proj.isNotNull().or(proj.isNull()) : proj.createDepartment.eq(findGameDto.getCreateDepartment()))
                //报名结束时间在用户选择的时间之前（结束=<用户选择的时间+现在）gt> lt<
                .where(findGameDto.getEndDate() == null ? proj.isNotNull().or(proj.isNull()) : proj.endTime.lt(newEndDate).or(proj.endTime.eq(newEndDate)))
                //报名现在还没结束
                .where(proj.endTime.after(now))
                //比赛类型
                .where(proj.type.eq(1))
                //审核已通过的
                .where(proj.status.eq(1))
                .fetchOne();


        return resDtoUtils.ProJ2PageDto(fetch, total,1);

    }



    @Override
    @Transactional
    public PageDto findProject(FindProjectDto dto) {
        Date now = DateUtil.parse(DateUtil.now(), "yyyy-MM-dd");
        //当为空时候自动设为2，避免前端错误
        Integer instituteType = dto.getInstituteType();

        if (instituteType == null) {
            dto.setInstituteType(2);
        }
        QProject proj = QProject.project;
        QProjectTag pt = QProjectTag.projectTag;
        List<Long> tagIds = null;


        /**
         * 判断是否为null
         */
        if (Optional.ofNullable(dto.getTags()).isPresent()) {
            //非空数组
            if (!dto.getTags().isEmpty()&&dto.getTags().size()!=0){
                //转换成ids数组
                tagIds = dto
                        .getTags()
                        .stream()
                        .map(item -> resDtoUtils.getTagIdButNotAdd(item))
                        .toList();
            }

        }



        //DONE:  2022/11/21 18:33 分页数据
        List<Project> fetch = jpaQueryFactory.select(proj)
                .distinct()
                .from(proj)
                .leftJoin(pt)
                .on(pt.projectId.eq(proj.projectId))
                //文学院还是理学院
                .where(dto.getInstituteType() == 2 ? proj.isNotNull().or(proj.isNull()) : proj.instituteType.eq(dto.getInstituteType()))
                //项目名字
                .where(dto.getProjectName()==null ? proj.isNotNull().or(proj.isNull()) : proj.projectName.like("%"+dto.getProjectName()+"%"))
                .where(dto.getProjectStartTime() == null ? proj.isNotNull().or(proj.isNull()) : proj.projectStartTime.after(dto.getProjectStartTime()))
                .where(dto.getContent()==null ? proj.isNotNull().or(proj.isNull()) : proj.content.eq(dto.getContent()))
                .where(tagIds == null ? proj.isNotNull().or(proj.isNull()) : pt.tagId.in(tagIds))
                //项目类型
                .where(proj.type.eq(0))
                //审核已通过的
                .where(proj.status.eq(1))
                //报名现在还没结束
                .where(proj.endTime.after(now))
                .orderBy(proj._super.updateDate.desc(),proj._super.createdDate.desc())
                .offset((long) (dto.getPageNum() - 1) * dto.getPageSize())
                .limit(dto.getPageSize())
                .fetch();



        //DONE:  2022/11/21 18:33 总计
        Long total = jpaQueryFactory.select(proj.countDistinct())
                .distinct()
                .from(proj)
                .leftJoin(pt)
                .on(pt.projectId.eq(proj.projectId))
                //文学院还是理学院
                .where(dto.getInstituteType() == 2 ? proj.isNotNull().or(proj.isNull()) : proj.instituteType.eq(dto.getInstituteType()))
                //项目名字
                .where(dto.getProjectName()==null ? proj.isNotNull().or(proj.isNull()) : proj.projectName.like("%"+dto.getProjectName()+"%"))
                .where(dto.getProjectStartTime() == null ? proj.isNotNull().or(proj.isNull()) : proj.projectStartTime.after(dto.getProjectStartTime()))
                .where(dto.getContent()==null ? proj.isNotNull().or(proj.isNull()) : proj.content.eq(dto.getContent()))
                .where(tagIds == null ? proj.isNotNull().or(proj.isNull()) : pt.tagId.in(tagIds))
                //项目类型
                .where(proj.type.eq(0))
                //报名现在还没结束
                .where(proj.endTime.after(now))
                //审核已通过的
                .where(proj.status.eq(1))
                .fetchOne();


        return resDtoUtils.ProJ2PageDto(fetch, total,0);
    }

    @Override
    @Transactional
    public ResProJDto addProject(AddProJDto dto,Long userId) throws Exception {
        Project project = dto.getProject();
        if (userId==null){
            log.warn("未认证用户在进行添加正在拦截");
            throw new SaveException("未认证用户在进行添加，已拦截");
        }
        project.setUserId(userId);
        //获取乐观锁
        Optional.ofNullable(project.getProjectId()).ifPresent(item->{
            log.info("本次操作为更新项目/比赛");
            QProject proj=QProject.project;
            Integer version = jpaQueryFactory.select(proj.version)
                    .from(proj)
                    .where(proj.projectId.eq(item))
                    .fetchOne();
            project.setVersion(version);
            log.info("获取乐观锁成功");
        });

        //先添加
        Project save = projectRepository.save(project);
        Long projectId = save.getProjectId();

        //如果是项目的话就会新增并且绑定标签
        if (("0".equals(dto.getType())||dto.getProject().getType()==0)
                &&(dto.getTags()!=null||StrUtil.isBlank(dto.getTags().get(0)))){
            //string转换成id，并且吧没有的新增了
            List<Long> tagIds = dto
                    .getTags()
                    .stream()
                    .map(item -> resDtoUtils.getTagIdByName(item))
                    .toList();
            //绑定
            resDtoUtils.bindTags(tagIds,projectId);
            log.info(save.getProjectName()+"[项目]"+"发布/修改成功");
            return ResProJDto
                    .builder()
                    .project(save)
                    .tags(resDtoUtils.getTags(save.getProjectId()))
                    .imgUrl(resDtoUtils.getImgUrl(save.getProjectId()))
                    .likes(resDtoUtils.countLikes(save.getProjectId()))
                    .build();
        }




        log.info(save.getProjectName()+"[比赛]"+"发布/修改成功");
        return ResProJDto
                .builder()
                .project(save)
                .tags(null)
                .likes(resDtoUtils.countLikes(save.getProjectId()))
                .imgUrl(resDtoUtils.getImgUrl(save.getProjectId()))
                .build();
    }



    @Override
    public List<ResProJDto> findAllLikeProJ(Long userId,Integer type) {
        QLikes likes=QLikes.likes;
        QProject proj=QProject.project;
        List<Project> fetch = jpaQueryFactory.select(proj)
                .from(proj)
                .leftJoin(likes)
                .on(proj.projectId.eq(likes.projectId))
                .where(likes.userId.eq(userId))
                .where(type==null ? proj.isNotNull().or(proj.isNull()) : proj.type.eq(type))
                //更新日期和创建日期排序
                .orderBy(likes._super.createdDate.desc(),likes._super.updateDate.desc())
                .fetch();

        return   fetch.stream().map(project -> {
                    try {
                        return ResProJDto
                                        .builder()
                                        .project(project)
                                        .tags(resDtoUtils.getTags(project.getProjectId()))
                                        .likes(resDtoUtils.countLikes(project.getProjectId()))
                                        .imgUrl(resDtoUtils.getImgUrl(project.getProjectId()))
                                        .build();
                    } catch (Exception e) {
                        throw new RuntimeException(e.getMessage());
                    }
                })
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ResProJDto addProjectLike(Long projectId, Long userId) throws Exception {
        QLikes likes=QLikes.likes;
        List<Likes> likeOne = jpaQueryFactory.selectFrom(likes)
                .where(likes.projectId.eq(projectId).and(likes.userId.eq(userId)))
                .fetch();
        if (likeOne.size()>0){
            log.warn(userId+"已收藏过["+projectId+"]项目");
            throw new RuntimeException("请勿重复收藏");
        }else {
            likesRepository.save(Likes
                    .builder()
                    .projectId(projectId)
                    .userId(userId)
                    .build());
        }
        QProject project=QProject.project;
        Project fetch = jpaQueryFactory.selectFrom(project)
                .where(project.projectId.eq(projectId))
                .fetchOne();

        return ResProJDto
                .builder()
                .project(fetch)
                .tags(resDtoUtils.getTags(projectId))
                .imgUrl(resDtoUtils.getImgUrl(projectId))
                .likes(resDtoUtils.countLikes(projectId))
                .build();
    }

    @Override
    public List<ResProJDto> findAllMakeProJ(Long userId) {
        QProject proj=QProject.project;
        List<Project> fetch = jpaQueryFactory.selectFrom(proj)
                .where(proj.userId.eq(userId))
                //创建时间先的先
                .orderBy(proj._super.updateDate.desc(),proj._super.createdDate.desc())
                .fetch();

        return  fetch.stream().map(project -> {
                    try {
                        return ResProJDto
                                        .builder()
                                        .project(project)
                                        .tags(resDtoUtils.getTags(project.getProjectId()))
                                        .imgUrl(resDtoUtils.getImgUrl(project.getProjectId()))
                                        .likes(resDtoUtils.countLikes(project.getProjectId()))
                                        .build();
                    } catch (Exception e) {
                        throw new RuntimeException(e.getMessage());
                    }
                })
                .collect(Collectors.toList());
    }

    @Override
    public ResProJDto findProjectById(Long projectId) {
        QProject project=QProject.project;
        Project fetch = jpaQueryFactory.selectFrom(project)
                .where(project.projectId.eq(projectId))
                .fetchOne();

        return ResProJDto
                .builder()
                .project(fetch)
                .tags(resDtoUtils.getTags(projectId))
                .likes(resDtoUtils.countLikes(projectId))
                .build();
    }

    @Override
    @Transactional
    public ResProJDto closeProject(Long projectId) {
        Date now=new Date();
        QProject project=QProject.project;
        jpaQueryFactory.update(project)
                .set(project.endTime,now)
                .execute();
        Project fetch = jpaQueryFactory.selectFrom(project)
                .where(project.projectId.eq(projectId))
                .fetchOne();
        return ResProJDto
                .builder()
                .project(fetch)
                .tags(resDtoUtils.getTags(projectId))
                .likes(resDtoUtils.countLikes(projectId))
                .build();
    }

    //判断当前操作用户是否是创建者
    @Override
    public boolean checkProJRole(Long projectId, Long userId) {
        QProject project=QProject.project;
        Long sum = jpaQueryFactory.select(project.userId.count())
                .from(project)
                .where(
                        project.projectId.eq(projectId)
                        .and(project.userId.eq(userId))
                ).fetchOne();
        if (sum==null){
            return true;
        }
        return sum <= 0;
    }
}
